package netx

import (
	"fmt"
	"github.com/pkg/errors"
	"io"
	"net"
	"net/http"
	"strings"
)

const (
	networkSpliter = "@"
)

func ParseNetwork(str string) (network, addr string, err error) {
	if idx := strings.Index(str, networkSpliter); idx == -1 {
		err = fmt.Errorf("addr: \"%s\" error, must be network@tcp:port or network@unixsocket", str)
		return
	} else {
		network = str[:idx]
		addr = str[idx+1:]
		return
	}
}

func ConvertAddr(addr string) (r string, err error) {
	iip, geterr := GetIntranetIp()
	if geterr != nil {
		err = errors.Wrap(geterr, "get intranet ip")
		return
	}
	ip := iip.String()
	addr = strings.ReplaceAll(addr, "localnet", ip)

	return addr, nil
}

func GetInternalIPByUDP() (string, error) {
	// 思路来自于Python版本的内网IP获取，其他版本不准确
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		return "", errors.New("internal IP fetch failed, detail:" + err.Error())
	}
	defer conn.Close()

	// udp 面向无连接，所以这些东西只在你本地捣鼓
	res := conn.LocalAddr().String()
	res = strings.Split(res, ":")[0]
	return res, nil
}

func GetIntranetIp() (ip net.IP, err error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	addresses := []net.IP{}
	for _, iface := range ifaces {

		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}

		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}

		addrs, adderr := iface.Addrs()
		if adderr != nil {
			continue
		}

		for _, addr := range addrs {
			var lip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				lip = v.IP
			case *net.IPAddr:
				lip = v.IP
			}

			if lip == nil || lip.IsLoopback() {
				continue
			}
			lip = lip.To4()
			if lip == nil {
				continue // not an ipv4 address
			}
			addresses = append(addresses, lip)
		}
	}
	if len(addresses) == 0 {
		return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses)
	}
	//only need first
	return addresses[0], nil
}
func GetExternalIP() (string, error) {
	// 有很多类似网站提供这种服务，这是我知道且正在用的
	// 备用：https://myexternalip.com/raw （cip.cc 应该是够快了，我连手机热点的时候不太稳，其他自己查）
	response, err := http.Get("http://ip.cip.cc")
	if err != nil {
		return "", errors.New("external IP fetch failed, detail:" + err.Error())
	}

	defer response.Body.Close()
	res := ""

	// 类似的API应当返回一个纯净的IP地址
	for {
		tmp := make([]byte, 32)
		n, err := response.Body.Read(tmp)
		if err != nil {
			if err != io.EOF {
				return "", errors.New("external IP fetch failed, detail:" + err.Error())
			}
			res += string(tmp[:n])
			break
		}
		res += string(tmp[:n])
	}

	return strings.TrimSpace(res), nil
}

func ConvertToZeroIP(addr string) string {
	if addr == "" {
		return addr
	}
	arr := strings.Split(addr, ":")
	port := arr[1]
	return "0.0.0.0:" + port
}

// 0.0.0.0:port
func ConvertZeroIPToPublic(addr string) string {
	return strings.ReplaceAll(addr, "0.0.0.0", GetPulicIP())
}

func GetPulicIP() string {
	conn, _ := net.Dial("udp", "8.8.8.8:80")
	defer conn.Close()
	localAddr := conn.LocalAddr().String()
	idx := strings.LastIndex(localAddr, ":")
	return localAddr[0:idx]
}

func GetPublicAddr(addr string) (x string) {
	arr := strings.Split(addr, ":")
	if len(arr) == 0 {
		return
	}
	if arr[0] == "" {
		x = GetPulicIP() + addr
	} else {
		x = addr
	}
	return
}
